
using UnityEngine;
using UnityEditor;
using System.Linq;

//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2024 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

namespace shaco.Instance.Editor
{
    public class AssetPreviewWindow
    {
        private UnityEditor.Editor _assetEditor;
        private Object _prevUnityAsset;
        private float _prevAnimationSpeed = float.MinValue;

        #region Animation动画相关参数
        private System.Type animationClipEditorType;
        private System.Type avatarPreviewType;
        private System.Type timeControlType;
        private System.Reflection.PropertyInfo _propertyInfoTimeControl;
        private System.Reflection.FieldInfo _filedInfoPlayBackSpeed;
        private object _avatarPreview;
        private object _timeControl;
        private bool _isWaitForAvatarPreviewReBuild_And_AutoPlay = false;
        private AnimationClip _currentAnimationClip = null;
        private bool _isAutoPlayAnimation = true;
        #endregion

        private const System.Reflection.BindingFlags PRIVATE_FIELD_BINDING_FLAGS = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetField;
        private const System.Reflection.BindingFlags PUBLIC_FIELD_BINDING_FLAGS = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetField;
        private const System.Reflection.BindingFlags PUBLIC_PROPERTY_BINDING_FLAGS = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty;

        public void ShowPreview(Object unityAsset, Vector2 size)
        {
            CheckAsset(unityAsset);

            if (null == _assetEditor)
                return;

            //当动态切换了动画文件后，avatar界面会被销毁等待创建，这里需要等待一下
            if (!_assetEditor.HasPreviewGUI())
                return;

            //在动态切换了动画文件后，需要等下动画avatar创建成功后再重新继续播放
            if (_isWaitForAvatarPreviewReBuild_And_AutoPlay && null != _currentAnimationClip)
            {
                AutoPlayAnimation(_currentAnimationClip);
                _isWaitForAvatarPreviewReBuild_And_AutoPlay = false;
            }

            using (new EditorGUILayout.HorizontalScope()) //水平布局
            {
                GUILayout.FlexibleSpace();//填充间隔
                _assetEditor.OnPreviewSettings(); //显示预览设置项
            }
            if (null != _currentAnimationClip)
            {
                GUI.changed = false;
                _isAutoPlayAnimation = EditorGUILayout.Toggle("Auto Play Animation", _isAutoPlayAnimation);
                if (GUI.changed)
                {
                    EditorPrefs.SetBool("AssetPreviewWindow._isAutoPlayAnimation", _isAutoPlayAnimation);
                }

                // AnimationMode.StartAnimationMode(); //为了播放正常播放预览动画而进行的设置
                // AnimationMode.BeginSampling( );
                _assetEditor.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(size.x, size.y), EditorStyles.whiteLabel);
                // AnimationMode.EndSampling();
                // AnimationMode.StopAnimationMode();
            }
            else
            {
                _assetEditor.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(size.x, size.y), EditorStyles.whiteLabel);
            }
        }

        //在界面关闭后请一定要调用该方法销毁预览窗口，否则在多次ShowPreview不同的对象几十次后
        //会出现'Unity Unable to allocate new scene culling mask'错误，导致预览窗口无法再创建了
        public void Cleanup()
        {
            if (null != _assetEditor)
            {
                Object.DestroyImmediate(_assetEditor);
                _assetEditor = null;
            }
        }

        public void SetAnimationSpeed(float speed)
        {
            if (_prevAnimationSpeed == speed)
                return;

            if (null == _propertyInfoTimeControl)
            {
                Debug.LogError("unsupport set animation speed");
                return;
            }

            if (null == _filedInfoPlayBackSpeed)
            {
                Debug.LogError("unsupport set animation speed, not found 'playbackSpeed' ");
                return;
            }

            _prevAnimationSpeed = speed;
            _filedInfoPlayBackSpeed.SetValue(_timeControl, speed);
        }

        public float GetAnimationSpeed()
        {
            if (null == _propertyInfoTimeControl)
            {
                Debug.LogError("unsupport get animation speed");
                return 1.0f;
            }

            if (null == _filedInfoPlayBackSpeed)
            {
                Debug.LogError("unsupport get animation speed, not found 'playbackSpeed' ");
                return 1.0f;
            }

            var retValue = _filedInfoPlayBackSpeed.GetValue(_timeControl);
            return (float)retValue;
        }

        private void CheckAsset(Object unityAsset)
        {
            if (_prevUnityAsset == unityAsset)
                return;
            _prevUnityAsset = unityAsset;
            _currentAnimationClip = null;
            _isAutoPlayAnimation = EditorPrefs.GetBool("AssetPreviewWindow._isAutoPlayAnimation", true);

            Cleanup();
            _assetEditor = UnityEditor.Editor.CreateEditor(unityAsset);

            var clip = unityAsset as AnimationClip; //如果是动画
            if (clip != null)
            {
                _assetEditor.HasPreviewGUI();
                _currentAnimationClip = clip;
                AutoPlayAnimation(clip);
                return;
            }
        }

        void AutoPlayAnimation(AnimationClip clip)
        {
            if (null == animationClipEditorType)
            {
                animationClipEditorType = System.Type.GetType("UnityEditor.AnimationClipEditor,UnityEditor");
                avatarPreviewType = System.Type.GetType("UnityEditor.AvatarPreview,UnityEditor");
                timeControlType = System.Type.GetType("UnityEditor.TimeControl,UnityEditor");
            }

            //这里不能获取全局的editor，可能刚好获取到上个在销毁中的
            //应该使用_assetEditor代替
            // var animationClipEditor = UnityEngine.Resources.FindObjectsOfTypeAll(animationClipEditorType).FirstOrDefault();
            // if (animationClipEditor == null) return;

            _avatarPreview = animationClipEditorType.GetField("m_AvatarPreview", PRIVATE_FIELD_BINDING_FLAGS)?.GetValue(_assetEditor);
            if (_avatarPreview == null)
            {
                _isWaitForAvatarPreviewReBuild_And_AutoPlay = true;
                return;
            }

            _timeControl = avatarPreviewType.GetField("timeControl", PUBLIC_FIELD_BINDING_FLAGS)?.GetValue(_avatarPreview);
            if (_timeControl == null) return;

            _propertyInfoTimeControl = timeControlType.GetProperty("playing", PUBLIC_PROPERTY_BINDING_FLAGS);
            if (_propertyInfoTimeControl == null) return;

            _filedInfoPlayBackSpeed = timeControlType.GetField("playbackSpeed", PUBLIC_FIELD_BINDING_FLAGS);

            if (_isAutoPlayAnimation)
                _propertyInfoTimeControl.SetValue(_timeControl, true);

            //设置帧数没用，需要设置时间
            // float length = clip.length;
            // float frameRate = clip.frameRate;
            // var totalFrame = Mathf.FloorToInt(length / (1 / frameRate));
            // var filedFps = avatarPreviewType.GetField("fps", PUBLIC_FIELD_BINDING_FLAGS);
            // filedFps.SetValue(_avatarPreview, totalFrame);

            //因unity默认动画最大时间是错的，需要重新设置下
            var filedStopTime = timeControlType.GetField("stopTime", PUBLIC_FIELD_BINDING_FLAGS);
            filedStopTime.SetValue(_timeControl, clip.length);

            _isWaitForAvatarPreviewReBuild_And_AutoPlay = false;
        }
    }
}